package foo.bar.wiki.plugins;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationContext;
import foo.bar.wiki.services.*;

/**
 * @author tmjee
 * @version $Date$ $Id$
 */
public class PluginManager implements InitializingBean, DisposableBean, ApplicationContextAware {

    private Class<UserRegistrationPlugin> userRegistrationPluginClass;
    private Class<UserActivityListenerPlugin> userActivityListenerPluginClass;
    private Class<SpaceListenerPlugin> spaceListenerPluginClass;
    private Class<PageListenerPlugin> pageListenerPluginClass;
    private Class<CommentListenerPlugin> commentListenerPluginClass;

    private UserRegistrationPlugin userRegistrationPlugin;
    private UserActivityListenerPlugin userActivityListenerPlugin;
    private SpaceListenerPlugin spaceListenerPlugin;
    private PageListenerPlugin pageListenerPlugin;
    private CommentListenerPlugin commentListenerPlugin;

    private PluginContext pluginContext;

    private ApplicationContext applicationContext;

    
    public PluginManager(
            Class<UserRegistrationPlugin> userRegistrationPlugin,
            Class<UserActivityListenerPlugin> userActivityListenerPlugin,
            Class<SpaceListenerPlugin> spaceListenerPlugin,
            Class<PageListenerPlugin> pageListenerPlugin,
            Class<CommentListenerPlugin> commentListenerPlugin
    ) throws PluginException, InstantiationException, IllegalAccessException {
        this.userRegistrationPluginClass = userRegistrationPlugin;
        this.userActivityListenerPluginClass = userActivityListenerPlugin;
        this.spaceListenerPluginClass = spaceListenerPlugin;
        this.pageListenerPluginClass = pageListenerPlugin;
        this.commentListenerPluginClass = commentListenerPlugin;
    }

    public void afterPropertiesSet() throws PluginException, IllegalAccessException, InstantiationException {
        this.pluginContext = new PluginContext(applicationContext);

        this.userRegistrationPlugin = instantiate(userRegistrationPluginClass, UserRegistrationPlugin.class);
        this.userActivityListenerPlugin = instantiate(userActivityListenerPluginClass, UserActivityListenerPlugin.class);
        this.spaceListenerPlugin = instantiate(spaceListenerPluginClass, SpaceListenerPlugin.class);
        this.pageListenerPlugin = instantiate(pageListenerPluginClass, PageListenerPlugin.class);
        this.commentListenerPlugin = instantiate(commentListenerPluginClass, CommentListenerPlugin.class);
    }

    public void destroy() {
        userRegistrationPlugin.destroy();
        userActivityListenerPlugin.destroy();
        spaceListenerPlugin.destroy();
        pageListenerPlugin.destroy();
        commentListenerPlugin.destroy();
    }

    protected <T extends Plugin,U extends Plugin> T instantiate(Class<T> clazz, Class<U> pluginClazz) throws IllegalAccessException, InstantiationException, PluginException {
        if (!pluginClazz.isAssignableFrom(clazz)) {
            throw new PluginException("Plugin ["+clazz+"] is not instance of ["+pluginClazz+"]");    
        }
        T plugin =  clazz.newInstance();
        plugin.init(pluginContext);
        return plugin;
    }

    public UserRegistrationPlugin getUserRegistrationPlugin() {
        return userRegistrationPlugin;
    }

    public UserActivityListenerPlugin getUserActivityListenerPlugin() {
        return userActivityListenerPlugin;
    }

    public SpaceListenerPlugin getSpaceListenerPlugin() {
        return spaceListenerPlugin;
    }

    public PageListenerPlugin getPageListenerPlugin() {
        return pageListenerPlugin;
    }

    public CommentListenerPlugin getCommentListenerPlugin() {
        return commentListenerPlugin;
    }


    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
